package com.abel.bigwater.data.jnrq

import com.abel.bigwater.model.JsonDateDeserializer
import com.abel.bigwater.model.JsonDateSerializer
import com.abel.bigwater.model.JsonHelper
import com.alibaba.fastjson.annotation.JSONField
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import org.joda.time.Period
import org.slf4j.LoggerFactory
import org.springframework.data.mongodb.core.index.CompoundIndex
import org.springframework.data.mongodb.core.index.CompoundIndexes
import org.springframework.data.mongodb.core.mapping.Document
import java.util.*

/**
 * 济南瑞泉RTU配置档案.
{
"address" : "53241",
"createDate" : ISODate("2020-04-09T13:58:53.168Z"),
"firmId" : "2108",
"readPeriod" : "PT01H",
"uploadPeriod" : "PT12H00M"
}
 */
@Document(collection = "JnrqDevice")
@CompoundIndexes(
        CompoundIndex(name = "idx_jnrq_device", unique = true, def = "{'firmId':1, 'address':1}"),
        CompoundIndex(name = "idx_jnrq_meter", unique = false, def = "{'firmId': 1, 'meterCode': 1}")
)
class JnrqDevice {
    /**
     * 站号, 5位数字. (协议: 4字节正数. 但后/高2个字节均为0)
     */
    var address: String? = null

    /**
     * 表号. 16位数字. (协议: 8字节BCD码)
     * 如 表号非空, 则: 表号与站号 绑定;
     * 其他站号 若上传该表号的数据, 则自动忽略.
     */
    var meterCode: String? = null

    /**
     * 插件的水司ID, 用来读取插件的配置库.
     * 插件的水司ID 不同于平台的水司ID. (因为实际运维中, 平台的多个水司可能使用同一个插件接收数据.)
     * 如: 济南瑞泉插件的水司ID=2108, 安吉水司的水司ID=2108. (两者也可以不同.)
     */
    var firmId: String? = null

    /**
     * 上传周期, 默认12小时. (注: 瑞泉的上传时间是自行控制的, 可能在周期内的任一时刻发起)
     */
    var uploadPeriod: String = "PT12H00M"

    /**
     * 采样周期, 默认1小时. (注:  瑞泉的采样时间是自行控制的, 可能在周期内的任一时刻发起.
     * 采样时间可能是 00'00", 也可能 59'59", 或其中某一时刻)
     */
    var readPeriod: String = "PT01H"

    /**
     * 站点名称
     */
    var devName: String? = null

    /**
     * 创建人账号
     */
    var createBy: String? = null

    /**
     * 创建日期, 在配置库中以ISO8701格式表示, 如:
     * "createDate" : ISODate("2019-02-27T17:02:03.366Z")
     */
    @JsonSerialize(using = JsonDateSerializer::class)
    @JsonDeserialize(using = JsonDateDeserializer::class)
    @JSONField(format = JsonHelper.FULL_DATE_FORMAT)
    var createDate: Date = Date()

    @org.springframework.data.annotation.Transient
    var readPeriodObj: Period = READ_PERIOD
        get() {
            if (readPeriod.isNullOrBlank()) return READ_PERIOD
            try {
                val p = Period.parse(readPeriod)
                if (p.toStandardSeconds().seconds < READ_PERIOD.toStandardSeconds().seconds) {
                    lgr.warn("too small read-period: {} in {} seconds / foramt: {}",
                            p, p.toStandardSeconds().seconds,
                            PERIOD_FMT)
                    return READ_PERIOD
                }
                return p
            } catch (ex: Exception) {
                lgr.warn("invalid read-period: {} / foramt: {}", ex.message, PERIOD_FMT)
                return READ_PERIOD
            }
        }

    @org.springframework.data.annotation.Transient
    var uploadPeriodObj: Period = UPLOAD_PERIOD
        get() {
            if (readPeriod.isNullOrBlank()) return UPLOAD_PERIOD
            try {
                val p = Period.parse(uploadPeriod)
                if (p.toStandardSeconds().seconds < UPLOAD_PERIOD.toStandardSeconds().seconds) {
                    lgr.warn("too small upload-period: {} in {} seconds / foramt: {}",
                            p, p.toStandardSeconds().seconds,
                            PERIOD_FMT)
                    return UPLOAD_PERIOD
                }
                return p
            } catch (ex: Exception) {
                lgr.warn("invalid upload-period: {} / foramt: {}", ex.message, PERIOD_FMT)
                return UPLOAD_PERIOD
            }
        }

    companion object {
        private val lgr = LoggerFactory.getLogger(JnrqDevice::class.java)

        val READ_PERIOD = Period(0, 10, 0, 0)
        val UPLOAD_PERIOD = Period(6, 0, 0, 0)
        val PERIOD_FMT = Period(1, 2, 3, 4, 5, 6, 7, 8)
    }
}